//=============================================================================
//
//   File : gui.launcher.cpp
//   Creation date : Sab 19 mar 2011 09:31:42 CET by Antonino G.Imbesi
//
//   This file is part of the QtGLauncher distribution
//   Copyright (C) 2011 Antonino G. Imbesi <grifisx at barmes dot org>
//                      Antonio Saporita: Mac OS X code implementation
//
//   This program is FREE software. You can redistribute it and/or
//   modify it under the terms of the GNU General Public License
//   as published by the Free Software Foundation; either version 2
//   of the License, or (at your opinion) any later version.
//
//   This program is distributed in the HOPE that it will be USEFUL,
//   but WITHOUT ANY WARRANTY; without even the implied warranty of
//   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
//   See the GNU General Public License for more details.
//
//   You should have received a copy of the GNU General Public License
//   along with this program. If not, write to the Free Software Foundation,
//   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
//=============================================================================

#include <QSettings>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QTreeWidgetItem>
#include <QStringList>
#include <QString>
#include <QIcon>
#include <QGraphicsDropShadowEffect>
#include <QApplication>
#include <QDesktopServices>
#include <QUrl>
#include <QFile>
#include <QIODevice>
#include <QLatin1String>
#include <QMessageBox>
#include <QProcess>
#include <QFileInfo>
#include <QDebug>
#include <QSystemTrayIcon>
#include <QMenu>
#include <QAction>
#include <QDir>
#include <QCloseEvent>
#include <qglobal.h>
#include <QDesktopWidget>

#include "qtg_listviewitem.h"
#include "qtg_treewidget.h"
#include "qtg_qpushbutton.h"
#include "qtg_lineedit.h"
#include "qtg_xml_reader.h"
#include "gui_laucher.h"
#include "qtg_appinstaller.h"
#include "qtg_config.h"

// Include to know free disk space and total disk space
#ifdef Q_WS_WIN32

#include <windows.h>

#else
// on Q_WS_X11 and Q_WS_MACX we need same include files
#include <sys/statvfs.h>

#endif


gui_laucher::gui_laucher(QWidget *parent)
    : QWidget(parent)
{

    setObjectName("mainWidget");

    m_appConf = new QSettings("./config/qtgconfig",QSettings::IniFormat);
    m_btnConf = new QSettings("./config/qtgbuttons",QSettings::IniFormat);
    m_recentsConf = new QSettings(m_appConf->value("Config/recentsFile").toString(),QSettings::IniFormat);

    m_pConfigDialog = new qtg_config(0,this);

    bool bFrameLess=m_appConf->value("Config/menuStyle").toBool();
    bool bTranslucentBg=m_appConf->value("Config/translucentWidget").toBool();
    bool bCloseBtnIsEnabled=m_appConf->value("Config/closeBtnIsEnabled").toBool();

    // Creo i layout
    QVBoxLayout *pTopLayout = new QVBoxLayout;
    QHBoxLayout *pMainLayout = new QHBoxLayout;
    QVBoxLayout *pLeftBoxLayout = new QVBoxLayout;
    QVBoxLayout *pRightBoxLayout = new QVBoxLayout;
    QHBoxLayout *pMiniButtonsLayout= new QHBoxLayout;
    QHBoxLayout *pTreeWLayout = new  QHBoxLayout;
    QStringList labels;

    // Creo l'interfaccia grafica e collego gli oggetti alle slot
    QWidget *pTreeWidgetBack = new QWidget;
    pTreeWidgetBack->setObjectName("TreeWBackwidget");
    pTreeWidgetBack->setMinimumHeight(400);
    pTreeWidgetBack->setLayout(pTreeWLayout);

    m_pTreeWidget = new qtg_QTreeWidget(pTreeWidgetBack);
    m_pTopWidget = new QWidget;
    pTreeWLayout->addWidget(m_pTreeWidget);

    m_pTopWidget->setObjectName("topWidget");
    m_pTopWidget->setFixedSize(404,60);

    m_pButtonsWidget = new QWidget;
    m_pButtonsWidget->setObjectName("buttonsWidget");

    QVBoxLayout *pVButtonsLayout = new QVBoxLayout(m_pButtonsWidget);

    labels << tr("Software");
    m_pTreeWidget->setHeaderLabels(labels);

    connect(m_pTreeWidget, SIGNAL(itemDoubleClicked (QTreeWidgetItem *, int)),
            this, SLOT(startProcess(QTreeWidgetItem *, int)));

    QStringList list =m_btnConf->childGroups();
    list.removeDuplicates();
    if(!list.isEmpty()){
        foreach(QString str, list){
            QString stra=str+"/";
            qtg_qpushbutton *pTemplateButton = new qtg_qpushbutton(m_pButtonsWidget,m_btnConf->value(stra+"text").toString());
            pTemplateButton->setIcon(QIcon(m_btnConf->value(stra+"icon").toString()));
            pTemplateButton->setFolderPath(m_btnConf->value(stra+"path").toString());
            connect(pTemplateButton, SIGNAL(clicked(QString)),
                    this, SLOT(openFolderPath(QString)));
            pVButtonsLayout->addWidget(pTemplateButton);
        }
    }
    pVButtonsLayout->addStretch();

    qtg_qpushbutton *pConfigBtn = new qtg_qpushbutton(m_pButtonsWidget,"");

    pConfigBtn->setIcon(QIcon("./themes/"+m_appConf->value("Config/themePath").toString()+"/config.ico"));
    pConfigBtn->setFixedWidth(32);
    pConfigBtn->setFixedHeight(32);
    pConfigBtn->setShortcut(QKeySequence(tr("Ctrl+J")));
    pConfigBtn->setToolTip(tr("Configura 'Ctrl+J'"));
    connect( pConfigBtn, SIGNAL(clicked()),
             this, SLOT(showOptionDialog()));
    pVButtonsLayout->addLayout(pMiniButtonsLayout);
    pMiniButtonsLayout->addStretch();
    pMiniButtonsLayout->addWidget(pConfigBtn);

    if(bCloseBtnIsEnabled){
        // Aggiungiamo un bottone per chiudere, nel caso di frameless è utile
        qtg_qpushbutton *pCloseBtn = new qtg_qpushbutton(m_pButtonsWidget,"");
        pCloseBtn->setIcon(QIcon("./themes/"+m_appConf->value("Config/themePath").toString()+"/close.ico"));
        pCloseBtn->setFixedWidth(32);
        pCloseBtn->setFixedHeight(32);
        pCloseBtn->setShortcut(QKeySequence(tr("Ctrl+O")));
        pCloseBtn->setToolTip(tr("Esci 'Ctrl+O'"));
        connect(pCloseBtn, SIGNAL(clicked()),
                this, SLOT(close()));

        pMiniButtonsLayout->addWidget(pCloseBtn);
    };

    qtg_lineedit *pFilterEdit = new qtg_lineedit;

    pFilterEdit->setIcon(QIcon("./themes/"+m_appConf->value("Config/themePath").toString()+"/search.png"));

    connect(pFilterEdit, SIGNAL(textChanged(const QString&)),
            this, SLOT(filterTree(const QString&)));



    // Aggiungo gli oggetti ai layout
    pTopLayout->addWidget(m_pTopWidget);
    pTopLayout->addLayout(pMainLayout);
    pTopLayout->setAlignment(m_pTopWidget,Qt::AlignHCenter);
    pMainLayout->addLayout(pLeftBoxLayout);
    pMainLayout->addLayout(pRightBoxLayout);
    pLeftBoxLayout->addWidget(pFilterEdit);

    pLeftBoxLayout->addWidget(pTreeWidgetBack);
    pRightBoxLayout->addWidget(m_pButtonsWidget);

    // Setto gli attributi della widget e richiamo le funzioni per iniziare tutto
    setLayout(pTopLayout);
    setmyStyleSheet();
    setWindowTitle(tr("QtGLauncher"));

    if(bFrameLess)
        setWindowFlags(Qt::FramelessWindowHint);
    if(bTranslucentBg){
        setAttribute(Qt::WA_TranslucentBackground);
        QGraphicsDropShadowEffect *pEffet = new QGraphicsDropShadowEffect;
        pEffet->setColor(QColor(0, 0, 0, 255));
        pEffet->setBlurRadius(20);

        setGraphicsEffect(pEffet);
    }

    setupTray();
#ifdef Q_WS_X11
    int w=m_appConf->value("Config/width").toInt();
    int h=m_appConf->value("Config/height").toInt();
    int y=m_pTray->geometry().y() ;
    int x=m_pTray->geometry().x() ;
    setGeometry(x+3,y+3,w,h);
#endif
#ifdef Q_WS_MACX
    int w=m_appConf->value("Config/width").toInt();
    int h=m_appConf->value("Config/height").toInt();
    int x = QApplication::desktop()->screenGeometry().width()-(h+125);
    setGeometry(x+75,0+3,w,h);
#endif
#ifdef Q_WS_WIN32
    int w =m_appConf->value("Config/width").toInt();
    int h =m_appConf->value("Config/height").toInt();
    int x,y;
    if(bFrameLess && bTranslucentBg)
    {
        x =    QApplication::desktop()->screenGeometry().width()-(h+125);
        y =    QApplication::desktop()->screenGeometry().height()-(w+155);
    }
    else
    {
        x =    QApplication::desktop()->screenGeometry().width()-(h+140);
        y =    QApplication::desktop()->screenGeometry().height()-(w+170);
    }
    setGeometry(x,y,w,h);
#endif
    open();
    show();
}

gui_laucher::~gui_laucher()
{
    m_pConfigDialog->~qtg_config();
}

void gui_laucher::loadConfig()
{

}

void gui_laucher::showOptionDialog()
{
    if(m_pConfigDialog->isVisible())
        m_pConfigDialog->hide();
    else
        m_pConfigDialog->show();
}

void gui_laucher::openFolderPath(QString szPath)
{
    QString filePath = (QApplication::applicationDirPath())+"/"+szPath;
    filePath=QDir::toNativeSeparators(filePath);
    QUrl url;
    url = QUrl::fromLocalFile(filePath);
    qDebug() << filePath;
    QDesktopServices::openUrl(url);
}




QStringList gui_laucher::getfsInfo()
{
    QStringList infoDiskList;
    int fKB = 1024;
    int fTotal;
    int fFree;

#ifdef Q_WS_WIN32
    ULARGE_INTEGER free,total;
    GetDiskFreeSpaceExA( 0 , &free , &total , NULL );

    fFree = static_cast<double>( static_cast<__int64>(free.QuadPart) ) / fKB;
    fTotal = static_cast<double>( static_cast<__int64>(total.QuadPart) ) / fKB;
#else
    // Q_WS_MACX  end Q_WS_X11
    struct statvfs stFileSystem;

    statvfs("./",&stFileSystem);
    fFree = stFileSystem.f_bavail * ( stFileSystem.f_bsize / fKB );
    fTotal = stFileSystem.f_blocks *  ( stFileSystem.f_bsize / fKB );
#endif

    infoDiskList << toHuman(fFree);
    infoDiskList << toHuman(fTotal);
    return infoDiskList;
}

QStringList gui_laucher::toHuman(float a)
{
    QStringList size;

    // Riporto a alla dimensione originaria;
    a=a*1024;
    // Inizializzo le variabili
    QString numsize;
    int loopsize=0;
    QString humansize;

    // Ne rendo la lettura umana controllando quante volte puo' essere diviso per 1024
    while(a>1024)
    {
        a=(a/1024);
        loopsize++;
    }
    // Uso le stringhe per convenienza
    numsize =numsize.setNum(a);
    numsize =numsize.replace(".",",");

    switch(loopsize){
    case 0:
        humansize=" b";
        break;
    case 1:
        humansize=" Kb";
        break;
    case 2:
        humansize=" Mb";
        break;
    case 3:
        humansize=" Gb";
        break;
    case 4:
        humansize=" Tb";
        break;
    default:
        break;

    }

    // Mi creao la lista di stringhe che avra'  al posto 0 il numero ed al posto 1 il valore Kb/Mb...
    size << numsize;
    size << humansize;

    return size;
}


void gui_laucher::setmyStyleSheet()
{
    QFile file("./themes/"+m_appConf->value("Config/themePath").toString()+"/style.qss");
    file.open(QIODevice::ReadWrite);
    QString styleSheet = QLatin1String(file.readAll());
    setStyleSheet(styleSheet);
}

void gui_laucher::open()
{
#ifdef Q_WS_WIN32
    QString fileName ="./config/qtglauncher_win.xml";
#endif
#ifdef Q_WS_X11
    QString fileName ="./config/qtglauncher.xml";
#endif
#ifdef Q_WS_MACX
    QString fileName ="./config/qtglauncher_macos.xml";
#endif
    QFile file(fileName);

    if (!file.open(QFile::ReadOnly | QFile::Text)) {
        QMessageBox::warning(this, tr("QtGLauncer"),
                             tr("Cannot read file %1:\n%2.")
                             .arg(fileName)
                             .arg(file.errorString()));
        return;
    }

    qtg_xml_reader reader(m_pTreeWidget);
    reader.read(&file);
    // Ho commentato il prossimo controllo perche' il file xml che usiamo termina in modo irregolare
    /*    if (!reader.read(&file)) {
          QMessageBox::warning(this, tr("QtGLauncer"),
                               tr("Parse error in file %1:\n\n%2")
                               .arg(fileName)
                               .arg(reader.errorString()));
      }*/
    if(m_appConf->value("Config/recentsIsEnabled").toBool())
        makeRecents();
}

void gui_laucher::startProcess(QTreeWidgetItem *a, int b)
{
    b=0;
    // Avvio il programma, prendo path e parametri dalle variabili settate nell'item
    qtg_QTreeWidgetItem * c = static_cast<qtg_QTreeWidgetItem *>(a);

    QString command;
    QStringList commandParameters;
    m_pProcess = new QProcess();
    command =  c->m_szProgramPath;
    QFileInfo fi(command);
    if(fi.exists())
    {
        qDebug()<< "EXIST";
        //  command.append("\"");
        // command.prepend("\"");
        if(c->m_szExeParams!="")
        {
            QString appPath= QApplication::applicationDirPath();
            appPath=appPath+"/"+c->m_szExeParams;
            commandParameters << appPath;
            qDebug () << command << "starting process whit params:" << appPath ;
            m_pProcess->start(command, commandParameters);
        }
        else
        {
            qDebug () << command << "starting process whitout params" ;
            m_pProcess->start(command);
        }
    }
    if(c->childCount()==0 && m_appConf->value("Config/recentsIsEnabled").toBool()){
        QStringList list =m_recentsConf->childGroups();

        foreach(QString str, list){           
            QString stra=str+"/";
            // Aumento l'id di tutti
            qDebug() <<"First" << m_recentsConf->value(stra+"id").toInt();
            int id =m_recentsConf->value(stra+"id").toInt();
            id++;
            m_recentsConf->beginGroup(str);
            m_recentsConf->setValue("id",id);
            m_recentsConf->endGroup();
            qDebug() << "After" << m_recentsConf->value(stra+"id").toInt();
            // se l'id ottenuto e' maggiore di 4 (max5elementi) elimino il menu' per far posto al nuovo
            if( m_recentsConf->value(stra+"id").toInt()>4 )
            {
                m_recentsConf->remove(str);
            }
        }
        m_recentsConf->beginGroup(c->text(0));
        m_recentsConf->setValue("exepath", c->m_szProgramPath);
        m_recentsConf->setValue("iconpath", c->m_szIconPath);
        m_recentsConf->setValue("params", c->m_szExeParams);
        m_recentsConf->setValue("id",1);
        m_recentsConf->endGroup();


    }
}
void gui_laucher::setupTray()
{
    m_pTray = new QSystemTrayIcon( this );
    m_pTrayIconMenu = new QMenu;
    QString szTip ="Spazio su disco disponibile\n";


    QStringList sizeInfo =getfsInfo();

    szTip.append(sizeInfo.at(0)).append(sizeInfo.at(1)).append(" / ").append(sizeInfo.at(2)).append(sizeInfo.at(3));

    createActions();

    m_pTray->setIcon (QIcon("./themes/"+m_appConf->value("Config/themePath").toString()+"/tray.ico"));
    m_pTray->setToolTip(szTip);

    connect(m_pTray, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(slotTrayActivated(QSystemTrayIcon::ActivationReason)));

    m_pTrayIconMenu->addAction(m_pMinimizeAction);
    m_pTrayIconMenu->addAction(m_pMaximizeAction);
    m_pTrayIconMenu->addAction(m_pRestoreAction);
    m_pTrayIconMenu->addSeparator();
    m_pTrayIconMenu->addAction(m_pQuitAction);
    m_pTray->setContextMenu(m_pTrayIconMenu);

    m_pTray->show();
}

void gui_laucher::slotTrayActivated(QSystemTrayIcon::ActivationReason reason)
{
    if (reason == QSystemTrayIcon::Trigger)
        slotToggleVisibility();
}



void gui_laucher::slotToggleVisibility()
{
    if(isHidden())
    {
        show();
        if(isMinimized())
        {
            if(isMaximized()) showMaximized();
            else  showNormal();
        }
        raise();
        activateWindow();
    }
    else hide();
}


void gui_laucher::closeEvent(QCloseEvent *e)
{
    e->accept();
    if (!m_pTray)  exit(1);
}

void gui_laucher::createActions()
{
    m_pMinimizeAction = new QAction(tr("Ri&duci"), this);
    m_pMinimizeAction->setIcon(QIcon("./themes/"+m_appConf->value("Config/themePath").toString()+"/bottom.png"));
    connect(m_pMinimizeAction, SIGNAL(triggered()), this, SLOT(hide()));

    m_pMaximizeAction = new QAction(tr("In&grandisci"), this);
    m_pMaximizeAction->setIcon(QIcon("./themes/"+m_appConf->value("Config/themePath").toString()+"/fullscreen.png"));
    connect(m_pMaximizeAction, SIGNAL(triggered()), this, SLOT(showMaximized()));


    m_pRestoreAction = new QAction(tr("&Ripristina"), this);
    m_pRestoreAction->setIcon(QIcon("./themes/"+m_appConf->value("Config/themePath").toString()+"/restore.png"));
    connect(m_pRestoreAction, SIGNAL(triggered()), this, SLOT(showNormal()));

    m_pQuitAction = new QAction(tr("&Esci"), this);
    m_pQuitAction->setIcon(QIcon("./themes/"+m_appConf->value("Config/themePath").toString()+"/2exit.png"));
    connect(m_pQuitAction, SIGNAL(triggered()), qApp, SLOT(quit()));
}
void gui_laucher::filterTree(const QString &filterString)
{
    m_pTreeWidget->filterIterator(filterString);
}
void gui_laucher::makeRecents()
{
    qtg_QTreeWidgetItem *pItemSeparator= new qtg_QTreeWidgetItem(m_pTreeWidget);

    pItemSeparator->setText(0, QString(30, 0xB7));
    m_pItemRecents= new qtg_QTreeWidgetItem(m_pTreeWidget);
    m_pItemRecents->setText(0,"Recenti");
    m_pItemRecents->setIcon(0,QIcon("./themes/"+m_appConf->value("Config/themepath").toString()+"/recents.png"));

    QStringList list =m_recentsConf->childGroups();
    list.removeDuplicates();
    if(!list.isEmpty()){
        foreach(QString str, list){
            QString stra=str+"/";
            QString pathexe=m_recentsConf->value(stra+"exepath").toString();
            QString params=m_recentsConf->value(stra+"params").toString();
            QString pathicon=m_recentsConf->value(stra+"iconpath").toString();

            qtg_QTreeWidgetItem *pItem= new qtg_QTreeWidgetItem(m_pItemRecents);
            pItem->setText(0,str);
            pItem->m_szProgramPath=pathexe;
            pItem->m_szExeParams=params;
            pItem->setIcon(0,QIcon(pathicon));

        }
    }
}

void gui_laucher::mousePressEvent(QMouseEvent *event)
{
    if (event->button() == Qt::LeftButton) {
        dragPosition = event->pos();
        event->accept();
    }
}

void gui_laucher::mouseMoveEvent(QMouseEvent *event)
{
    if (event->buttons() & Qt::LeftButton) {
        move(event->globalPos() - dragPosition);
        event->accept();
    }
}
/*
void gui_laucher::enterEvent(QEvent *event)
{
 //   setWindowOpacity(1.0);
}

void gui_laucher::leaveEvent(QEvent *event)
{
   // setWindowOpacity(0.8);
}
*/
